package intf.impl;

import algo.Geom;
import intf.ICommonItem;
import intf.ILine;
import intf.IPoint;

/**
 * Created by IntelliJ IDEA. User: sigolaev_va Date: 06.02.2013 Time: 9:37:33 To
 * change this template use File | Settings | File Templates.
 */
public class LineImpl implements ILine
{
	private IPoint m_start, m_end;
	private byte m_type;
	protected boolean m_done;
	private String m_name;
	private Geom m_geom = new Geom();

	public LineImpl( IPoint start, IPoint end, byte type)
	{
		this( start, end);
		switch (type)
		{
		case Geom.TYPE_WELL_ITEM:
		case Geom.TYPE_STEINER_ITEM:
		case Geom.TYPE_COLLECT_ITEM:
			m_type = type;
			break;
		default:
			m_type = Geom.TYPE_NONE;
		}
	}

	public LineImpl( IPoint start, IPoint end)
	{
		m_start = start;
		m_end = end;
		m_type = Geom.TYPE_WELL_ITEM;
	}

	/**
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 */
    public LineImpl( double x1, double y1, double x2, double y2)
    {
    	this ( new PointImpl(x1, y1), new PointImpl(x2, y2));
    }

	public IPoint startPoint()
	{
		return m_start;
	}

	public IPoint endPoint()
	{
		return m_end;
	}

	public double distance( IPoint point )
	{
		return point.distanceTo(this);
	}

	public double length()
	{
		return Geom.distance(m_start.X(), m_start.Y(), m_end.X(), m_end.Y());
	}

	public boolean preprocessed()
	{
		return m_done;
	}

	public void markPreprocessed()
	{
		m_done = true;
	}

	public boolean isLine()
	{
		return true;
	}

	public boolean isPoint()
	{
		return false; // To change body of implemented methods use File |
					  // Settings | File Templates.
	}

	public double distanceFrom( ICommonItem item )
	{
		if ( item.isPoint() )
			return item.distanceFrom(this);

		// not point, so line, find nearest distance to any of point of the line
		double startDist = ((ILine) item).startPoint().distanceFrom(this);
		double endDist = ((ILine) item).endPoint().distanceFrom(this);
		final double minDist1 = Math.min(startDist, endDist);
		startDist = this.startPoint().distanceFrom(item);
		endDist = this.endPoint().distanceFrom(item);
		final double minDist2 = Math.min(startDist, endDist);
		return Math.min(minDist1, minDist2);
	}

	public ICommonItem buildConnectItem( IPoint pnt )
	{
		IPoint newPnt = new PointImpl(Geom.TYPE_STEINER_ITEM);
		double dist = m_geom.perpendicular(newPnt, pnt, m_start, m_end);
		if ( dist <= 0.0 ) // we are connecting to start point
		{
			return m_start.buildConnectItem(pnt);
		}
		else if ( dist >= 1.0 ) // connecting to the end point
		{
			return m_end.buildConnectItem(pnt);
		}

		/**
		 * let type of line be of designated input point type. Later I can
		 * change this logic, depending on debugging issues. Also calculate cost
		 * distance to the main collector point
		 */
		return new LineImpl(newPnt, pnt, pnt.type());
	}

	public byte type()
	{
		return m_type;
	}

	public String name()
	{
		return m_name;
	}
}
